﻿using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using ESoft.Office.Excel.BO;
using ESoft.Office.Excel.DataAnnotations;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;

namespace ESoft.Office.Excel.Impl
{
    public class ExcelService : IExcelService
    {
        public Task ExportAsync<T>(ExportInputBo<T> inputBo) where T : new()
        {
            Type t = typeof(T);
            var workbook = new XSSFWorkbook();
            var workSheetAttr = t.GetCustomAttributes<WorkSheetAttribute>(true).FirstOrDefault();
            var sheet = workbook.CreateSheet(workSheetAttr?.SheetName);
            sheet.DefaultColumnWidth = 20;
            sheet.ForceFormulaRecalculation = true;


            var headFont = workbook.CreateFont();
            headFont.IsBold = true;
            var headStyle = workbook.CreateCellStyle();
            headStyle.Alignment = HorizontalAlignment.Center;
            headStyle.BorderBottom = BorderStyle.Thin;
            headStyle.BorderLeft = BorderStyle.Thin;
            headStyle.BorderRight = BorderStyle.Thin;
            headStyle.BorderTop = BorderStyle.Thin;
            headStyle.SetFont(headFont);

            var properties = t.GetProperties().Where(x => x.GetCustomAttributes<ColumnAttribute>(true).Any())
                .OrderBy(x => x.GetCustomAttributes<ColumnAttribute>().First().Sort);

            var columns = properties.SelectMany(x => x.GetCustomAttributes<ColumnAttribute>()).OrderBy(x => x.Sort);

            var rowIndex = 0;
            var row = sheet.CreateRow(rowIndex);
            var columnIndex = 0;
            foreach (var column in columns)
            {
                sheet.SetColumnWidth(columnIndex, 30 * 256);
                var cell = row.CreateCell(columnIndex++);
                cell.SetCellValue(column.Title);
                cell.CellStyle = headStyle;
            }

            rowIndex++;

            var cellStyle = workbook.CreateCellStyle();
            cellStyle.BorderBottom = BorderStyle.Thin;
            cellStyle.BorderLeft = BorderStyle.Thin;
            cellStyle.BorderRight = BorderStyle.Thin;
            cellStyle.BorderTop = BorderStyle.Thin;

            foreach (var dataItem in inputBo.DataList)
            {
                var itemRow = sheet.CreateRow(rowIndex);
                var index = 0;

                foreach (var propertyInfo in properties)
                {
                    var value = propertyInfo.GetValue(dataItem);
                    var cell = itemRow.CreateCell(index);
                    cell.SetCellValue(value.ToString());
                    cell.CellStyle = cellStyle;
                    index++;
                }

                rowIndex++;
            }

            var fileStream = new FileStream(inputBo.OutputPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            workbook.Write(fileStream);
            fileStream.Close();

            return Task.CompletedTask;
        }
    }
}